package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.TestLeave;
import com.ruoyi.system.enums.FlowType;
import com.ruoyi.system.mapper.TestLeaveMapper;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.system.service.ITestLeaveService;
import com.warm.flow.core.FlowFactory;
import com.warm.flow.core.dto.FlowParams;
import com.warm.flow.core.entity.Instance;
import com.warm.flow.core.entity.User;
import com.warm.flow.core.enums.SkipType;
import com.warm.flow.core.service.InsService;
import com.warm.flow.core.service.TaskService;
import com.warm.flow.core.utils.IdUtils;
import com.warm.flow.core.utils.StreamUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * OA 请假申请Service业务层处理
 *
 * @author ruoyi
 * @date 2024-03-07
 */
@Service
public class TestLeaveServiceImpl implements ITestLeaveService
{
    @Autowired
    private TestLeaveMapper testLeaveMapper;

    @Resource
    private InsService insService;

    @Resource
    private TaskService taskService;

    @Resource
    private ISysDictTypeService sysDictTypeService;

    /**
     * 查询OA 请假申请
     *
     * @param id OA 请假申请主键
     * @return OA 请假申请
     */
    @Override
    public TestLeave selectTestLeaveById(String id)
    {
        return testLeaveMapper.selectTestLeaveById(id);
    }

    /**
     * 查询OA 请假申请列表
     *
     * @param testLeave OA 请假申请
     * @return OA 请假申请
     */
    @Override
    public List<TestLeave> selectTestLeaveList(TestLeave testLeave)
    {
        return testLeaveMapper.selectTestLeaveList(testLeave);
    }

    /**
     * 新增OA 请假申请
     *
     * @param testLeave OA 请假申请
     * @return 结果
     */
    @Override
    public int insertTestLeave(TestLeave testLeave)
    {
        String id = IdUtils.nextIdStr();
        testLeave.setId(id);
        LoginUser user = SecurityUtils.getLoginUser();
        FlowParams flowParams = FlowParams.build().flowCode(getFlowType(testLeave))
                .handler(user.getUser().getUserId().toString());
        // 流程变量
        Map<String, Object> variable = new HashMap<>();
        variable.put("testLeave", testLeave);
        variable.put("flag", String.valueOf(testLeave.getDay()));
        flowParams.variable(variable);

        Instance instance = insService.start(id, flowParams);
        testLeave.setInstanceId(instance.getId());
        testLeave.setNodeCode(instance.getNodeCode());
        testLeave.setNodeName(instance.getNodeName());
        testLeave.setFlowStatus(instance.getFlowStatus());
        testLeave.setCreateTime(DateUtils.getNowDate());
        // 新增抄送人方法
        //TODO 发送通知
        if (StringUtils.isNotNull(testLeave.getAdditionalHandler())) {
            List<User> users = FlowFactory.userService().structureUser(instance.getId()
                    , testLeave.getAdditionalHandler(), "4");
            FlowFactory.userService().saveBatch(users);
        }


        return testLeaveMapper.insertTestLeave(testLeave);
    }

    /**
     * 修改OA 请假申请
     *
     * @param testLeave OA 请假申请
     * @return 结果
     */
    @Override
    public int updateTestLeave(TestLeave testLeave)
    {
        testLeave.setUpdateTime(DateUtils.getNowDate());
        return testLeaveMapper.updateTestLeave(testLeave);
    }

    /**
     * 批量删除OA 请假申请
     *
     * @param ids 需要删除的OA 请假申请主键
     * @return 结果
     */
    @Override
    public int deleteTestLeaveByIds(String[] ids)
    {
        List<TestLeave> testLeaveList = testLeaveMapper.selectTestLeaveByIds(ids);
        if (testLeaveMapper.deleteTestLeaveByIds(ids) > 0) {
            List<Long> instanceIds = testLeaveList.stream().map(TestLeave::getInstanceId).collect(Collectors.toList());
            return insService.remove(instanceIds) ? 1: 0;
        }
        return 0;
    }

    /**
     * 删除OA 请假申请信息
     *
     * @param id OA 请假申请主键
     * @return 结果
     */
    @Override
    public int deleteTestLeaveById(String id)
    {
        return testLeaveMapper.deleteTestLeaveById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int submit(String id) {
        TestLeave testLeave = testLeaveMapper.selectTestLeaveById(id);
        LoginUser user = SecurityUtils.getLoginUser();
        FlowParams flowParams = FlowParams.build().handler(user.getUser().getUserId().toString())
                .skipType(SkipType.PASS.getKey());
        List<SysRole> roles = user.getUser().getRoles();
        List<String> permissionList = new ArrayList<>();
        if (Objects.nonNull(roles)) {
            permissionList = roles.stream().map(role -> "role:" + role.getRoleId()).collect(Collectors.toList());
        }
        permissionList.add("dept:" + SecurityUtils.getLoginUser().getUser().getDeptId());
        permissionList.add(user.getUser().getUserId().toString());
        flowParams.permissionFlag(permissionList);
        // 流程变量
        Map<String, Object> variable = new HashMap<>();
        variable.put("testLeave", testLeave);
        flowParams.variable(variable);

        Instance instance = insService.skipByInsId(testLeave.getInstanceId(), flowParams);
        testLeave.setNodeCode(instance.getNodeCode());
        testLeave.setNodeName(instance.getNodeName());
        testLeave.setFlowStatus(instance.getFlowStatus());
        testLeave.setUpdateTime(DateUtils.getNowDate());
        return testLeaveMapper.updateTestLeave(testLeave);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int handle(TestLeave testLeave, Long taskId, String skipType, String message, String nodeCode) {
        // 设置流转参数
        LoginUser user = SecurityUtils.getLoginUser();
        FlowParams flowParams = FlowParams.build().handler(user.getUser().getUserId().toString())
                .skipType(skipType)
                .nodeCode(nodeCode)
                .message(message);
        List<SysRole> roles = user.getUser().getRoles();
        List<String> permissionList = new ArrayList<>();
        if (Objects.nonNull(roles)) {
            permissionList = roles.stream().map(role -> "role:" + role.getRoleId()).collect(Collectors.toList());

        }
        permissionList.add("dept:" + SecurityUtils.getLoginUser().getUser().getDeptId());
        permissionList.add(user.getUser().getUserId().toString());
        flowParams.permissionFlag(permissionList);

        // 流程变量
        Map<String, Object> variable = new HashMap<>();
        variable.put("testLeave", testLeave);
        variable.put("flag", String.valueOf(testLeave.getDay()));
        flowParams.variable(variable);
        // 请假信息存入flowParams
        flowParams.hisTaskExt(JSON.toJSONString(testLeave));
        Instance instance = taskService.skip(taskId, flowParams);
        // 更新请假表
        testLeave.setNodeCode(instance.getNodeCode());
        testLeave.setNodeName(instance.getNodeName());
        testLeave.setFlowStatus(instance.getFlowStatus());
        return testLeaveMapper.updateTestLeave(testLeave);
    }

    @Override
    public int termination(Long instanceId) {
        FlowParams flowParams = new FlowParams();
        flowParams.message("终止流程").handler(SecurityUtils.getLoginUser().getUserId().toString());
        Instance instance = insService.termination(instanceId, flowParams);
        if (instance == null) {
            throw new ServiceException("流程实例不存在");
        }
        TestLeave testLeave = testLeaveMapper.selectTestLeaveById(instance.getBusinessId());
        testLeave.setNodeCode(instance.getNodeCode());
        testLeave.setNodeName(instance.getNodeName());
        testLeave.setFlowStatus(instance.getFlowStatus());

        return testLeaveMapper.updateTestLeave(testLeave);
    }

    private String  getFlowType(TestLeave testLeave) {
        List<SysDictData> leaveType = sysDictTypeService.selectDictDataByType("leave_type");
        Map<String, String> map = StreamUtils.toMap(leaveType, SysDictData::getDictValue, SysDictData::getRemark);
        return map.get(testLeave.getType().toString());
    }
}
